package com.cctc.rds.raft.core.rpc.election.impl;

import com.cctc.rds.raft.core.RaftCluster;
import com.cctc.rds.raft.core.log.Log;
import com.cctc.rds.raft.core.log.LogService;
import com.cctc.rds.raft.core.node.Node;
import com.cctc.rds.raft.core.node.NodeVoter;
import com.cctc.rds.raft.core.rpc.election.ElectionRpc;
import com.cctc.rds.raft.core.rpc.election.ElectionRpcRequest;
import com.cctc.rds.raft.core.rpc.election.ElectionRpcResponse;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * Raft 竞选 [投票] 实现类。
 * 前提：当 Raft 节点收到其他节点的 [拉票] 请求时，将会触发自身的竞选 [投票] 逻辑。
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ElectionRpcResponseImpl implements ElectionRpc {
    private int nodeId;
    private LogService logService;

    @Override
    public ElectionRpcResponse elect(ElectionRpcRequest request) {
        ElectionRpcResponse response = ElectionRpcResponse.builder().build();
        Node curNode = RaftCluster.getNode(nodeId);
        if (curNode.getCurTerm() > request.getLastCommitLogTerm()) {
            response.setGranted(false);
            response.setTerm(curNode.getCurTerm());
            return response;
        }
        NodeVoter voter = curNode.getVoterHolder().get(request.getTerm());
        if (voter.lock(request.getNodeId())) {
            response.setGranted(true);
            response.setTerm(request.getTerm());
            return response;
        } else {
            Log log = logService.index(curNode.curCommitLogIndex());
            if (log == null && request.getLastCommitLogIndex() == -1 && request.getLastCommitLogTerm() == -1) {
                response.setGranted(true);
                response.setTerm(request.getTerm());
                return response;
            }
            if (log != null && log.getIndex() == request.getLastCommitLogIndex() && log.getTerm() == request.getLastCommitLogTerm()) {
                response.setGranted(true);
                response.setTerm(request.getTerm());
                return response;
            }
        }
        response.setGranted(false);
        response.setTerm(request.getTerm());
        return response;
    }
}
